﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Dotnet.Utils.Utility.ObjectExtensions.Number
{
    public static class DecimalExtensions
    {
        /// <summary>
        /// 获取数据的百分比
        /// </summary>
        /// <param name="str">数据</param>
        /// <returns></returns>
        private static decimal GetPercentValue(string str)
        {
            return GetValue(str) * 100;
        }

        /// <summary>
        /// 获取数据的百分比
        /// </summary>
        /// <param name="str">数据</param>
        /// <returns></returns>
        private static string GetPercentStringValue(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return string.Empty;
            }
            return (GetValue(str) * 100).ToString();
        }

        /// <summary>
        /// 去掉小数部分
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal Truncate(this decimal value)
        {
            return decimal.Truncate(value);
        }

        /// <summary>
        /// 去掉小数点后面的0
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal Normalize(this decimal value)
        {
            return value / 1.000000000000000000000000000000000m;
        }

        /// <summary>
        /// 判断是否是整数(有没有小数点)
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool IsInteger(this decimal value)
        {
            return value % 1 == 0;
        }

        /// <summary>
        /// 小数点截取不四舍五入
        /// </summary>
        /// <param name="value"></param>
        /// <param name="digits">小数点位数</param>
        /// <returns></returns>
        public static decimal ToDecimalNoRound(this decimal value, int digits = 2)
        {
            return Math.Floor(value * (decimal)Math.Pow(10, digits)) / (decimal)Math.Pow(10, digits);
        }

        /// <summary>
        /// 小数点截取四舍五入
        /// </summary>
        /// <param name="num"></param>
        /// <param name="digits">小数位数</param>
        /// <returns></returns>
        public static decimal ToDecimal(this decimal num, int digits = 2) => Math.Round(num, digits, MidpointRounding.AwayFromZero);


        /*
          四舍六入规则:
            四舍六入五考虑，
            五后非零就进一，
            五后皆零看奇偶，
            五前为偶应舍去，
            五前为奇要进一。
        */
        /// <summary>
        /// 4舍6入5成双
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal FormatDecimal(decimal value, int formatLength = 2)
        {
            return decimal.Round(value, formatLength);
        }

        /// <summary>
        /// 4舍6入5成双
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string FormatDecimalToString(decimal value, int formatLength = 2)
        {
            return Convert.ToString(decimal.Round(value, formatLength));
        }


        /// <summary>
        /// 保留小数转字符串
        /// </summary>
        /// <param name="input"></param>
        /// <param name="digits">保留小数位数</param>
        /// <param name="round">是否四舍五入</param>
        /// <returns>截取指定小数位数后的数量字符串</returns>
        public static string ToDecimalString(this object input, int digits = 2, bool round = false)
        {
            if (input != null && decimal.TryParse(input.ToString(), out decimal decimalValue))
            {
                return decimalValue.ToDecimalString(digits, round);
            }
            return string.Empty;
        }

        /// <summary>
        /// decimal保留指定位数小数
        /// </summary>
        /// <param name="num">原始数量</param>
        /// <param name="digits">保留小数位数</param>
        /// <param name="round">是否四舍五入</param>
        /// <returns>截取指定小数位数后的数量字符串</returns>
        public static string ToDecimalString(this decimal num, int digits = 2, bool round = false)
        {
            string format = digits < 0 ? string.Empty : $"f{digits}";
            return round ? num.ToDecimal(digits).ToString(format) : num.ToDecimalNoRound(digits).ToString(format);
        }

        /// <summary>
        /// decimal保留指定位数小数(整数不保留小数位数)
        /// </summary>
        /// <param name="num">原始数量</param>
        /// <param name="digits">保留小数位数</param>
        /// <param name="round">是否四舍五入</param>
        /// <returns>截取指定小数位数后的数量字符串</returns>
        public static string ToDecimalIntegerString(this decimal num, int digits = 2, bool round = false)
        {
            int precision = digits;
            if (num.IsInteger())
            {
                precision = 0;
            }
            return num.ToDecimalString(precision, round);
        }

        /// <summary>
        /// 提取分数的两个值
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static (decimal, decimal)? GetFractionDecimalValues(this string input)
        {
            if (string.IsNullOrWhiteSpace(input))
            {
                return null;
            }

            string[] parts = input.Split('/');

            if (parts.Length == 2 &&
                decimal.TryParse(parts[0].Trim(), out decimal decimal1) &&
                decimal.TryParse(parts[1].Trim(), out decimal decimal2))
            {
                return (decimal1, decimal2);
            }
            else
            {
                return null;
            }

            //调用
            //(decimal, decimal)? result = "2.1/2.2".GetFractionDecimalValues();
            //if (result.HasValue)
            //{
            //    var (numerator, denominator) = result.Value;
            //}
        }

        /// <summary>
        /// 获取平均值
        /// </summary>
        /// <param name="datas"></param>
        /// <returns></returns>
        public static decimal GetAverage(params decimal[] datas)
        {
            List<decimal> result = new List<decimal>();
            foreach (decimal data in datas)
            {
                if (data != 0)
                {
                    result.Add(data);
                }
            }
            return result.Average();
        }

        /// <summary>
        /// 获取减法的绝对值
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <returns></returns>
        public static decimal FormateSubtractionSign(decimal value1, decimal value2)
        {
            return Math.Abs(value1 - value2);
        }

        #region 获取值
        /// <summary>
        /// 字符串转小数
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal GetValue(string value)
        {
            if (!string.IsNullOrEmpty(value) && decimal.TryParse(value, out decimal result))
            {
                return result;
            }
            return decimal.Zero;
        }

        /// <summary>
        /// 字符串转小数
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal GetDecimal(string value)
        {
            if (!string.IsNullOrEmpty(value) && decimal.TryParse(value, out decimal result))
            {
                return result;
            }
            return decimal.Zero;
        }

        public static decimal GetValue(decimal? obj)
        {
            if (obj.HasValue)
            {
                return obj.Value;
            }
            else
            {
                return int.MinValue;
            }
        }

        public static string FormatValueToString(decimal value, int formatLength = 2)
        {
            return decimal.Round(value, formatLength, MidpointRounding.ToEven).ToString();
        }
        public static decimal FormatValueToDecimal(decimal value, int formatLength = 2)
        {
            return decimal.Round(value, formatLength, MidpointRounding.ToEven);
        }
        #endregion

        #region 除法
        /// <summary>
        /// 除法 4舍6入5成双
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <returns></returns>
        public static string FormatDivDecimalToString(decimal value1, decimal value2, int formatLength = 2)
        {
            if (value2 != 0)
            {
                return Convert.ToString(decimal.Round(value1 / value2, formatLength));
            }
            else
            {
                return "0";
            }
        }

        /// <summary>
        /// 除法 
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <returns></returns>
        public static decimal FormatDivDecimal(decimal value1, decimal value2)
        {
            if (value2 != 0)
            {
                return value1 / value2;
            }
            else
            {
                return 0m;
            }
        }

        /// <summary>
        /// 除法 
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <param name="num">小数位数,小于等于0则保留整数</param>
        /// <returns></returns>
        public static decimal FormatDivDecimal(decimal value1, decimal value2, int num)
        {
            if (value2 != 0)
            {
                if (num > 0)
                {
                    return decimal.Round(value1 / value2, num);
                }
                else
                {
                    return decimal.Round(value1 / value2);
                }
            }
            else
            {
                return 0m;
            }
        }

        /// <summary>
        /// 除法 
        /// </summary>
        /// <param name="value1"></param>
        /// <param name="value2"></param>
        /// <param name="num">小数位数,小于等于0则保留整数</param>
        /// <returns></returns>
        public static string FormatPercentToStr(decimal value1, decimal value2, int num)
        {
            if (value1 != 0 && value2 != 0)
            {
                if (num > 0)
                {
                    return (decimal.Round(value1 / value2, num) * 100).ToString("0.0");
                }
                else
                {
                    return (decimal.Round(value1 / value2) * 100).ToString("0.0");
                }
            }
            else
            {
                return "0";
            }
        }
        public static string FormatToString(decimal value)
        {
            return value.ToString();
        }

        #endregion

        /// <summary>
        /// 数值修约
        /// </summary>
        /// <param name="formateType"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static decimal FormateByCustom(修约方式 formateType, decimal value)
        {
            decimal result = 0m;
            if (formateType == 修约方式.修约间隔100)
            {
                decimal v1 = value / 100m;
                result = Math.Round(v1, 0) * 100;
            }
            else if (formateType == 修约方式.修约间隔10)
            {
                decimal v1 = value / 10m;
                result = Math.Round(v1, 0) * 10;
            }
            else if (formateType == 修约方式.修约间隔5)
            {
                decimal v1 = value / 5m;
                result = Math.Round(v1, 0) * 5;
            }
            else if (formateType == 修约方式.修约间隔1)
            {
                result = Math.Round(value, 0);
            }
            else if (formateType == 修约方式.修约间隔百分之1)
            {
                result = Math.Round(value, 2);
            }
            else if (formateType == 修约方式.修约间隔百分之0点5)
            {
                decimal v1 = value / 5m;
                result = Math.Round(v1, 3) * 5;
            }
            else if (formateType == 修约方式.修约间隔百分之0点1)
            {
                result = Math.Round(value, 3);
            }
            else if (formateType == 修约方式.修约间隔零点5)
            {
                decimal v1 = value * 2;
                result = Math.Round(v1, 0) / 2m;
            }
            else if (formateType == 修约方式.修约间隔零点零5)
            {
                decimal v1 = value * 20;
                result = Math.Round(v1, 0) / 20m;
            }
            return result;
        }

    }

    public enum 修约方式
    {
        修约间隔100 = 1,
        修约间隔10 = 2,
        修约间隔5 = 3,
        修约间隔1 = 4,
        修约间隔百分之1 = 5,
        修约间隔百分之0点5 = 6,
        修约间隔百分之0点1 = 7,
        修约间隔零点5 = 8,
        修约间隔零点零5 = 9,
    }
}